import struct
import quantities as quantities
from auxillaries.unit_converter import UnitConverter
from pyFAMOUSO.event import Event

class ExtendedEventHandling():
    
    data_types =    {'int16' :['h','short',[-32768, 32768]],
                     'u_int16' :['h','short',[0, 65535 ]],
                     'int32'   :['i', 'integer',[-2147483648, 2147483647]],
                     'u_int32'   :['i', 'integer',[0, 4294967295]],
                     'float' :['f', 'float', [-2147483648, 2147483647]],
                     'u_int8':['B', 'unsigned byte',[0, 255]], 
                     'int8':['b', 'signed byte',[-128, 127]]}
    
    def __init__(self, properties):
        self.properties=properties
        self.individual_validity=[]
        for element in self.properties.eventFormat:
            element['Value']=[]
            
    def reset_structure(self):
        for element in self.properties.eventFormat:
            if element['Static']==False:
                element['Value']=[]
        self.individual_validity=[]

    def __repr__(self):
        output="\n      Entry     |  Value \n ------------------------------\n"
        for element in self.properties.eventFormat:
            output+="   {0:12} |".format(element["Name"])
            if type(element['Value']) is list:
                if element['Value']==[]:
                    for i in range(0, element['Size']):
                        if i>0:
                            output+=('                |    xxx\n')
                        else:
                            output+=('    xxx\n')                    
                    
                else:
                    for i in range(0, len(element['Value'])):
                        if i>0:
                            output+=('                |  %7.2f\n'%element['Value'][i])
                        else:
                            output+=('  %7.2f\n'%element['Value'][i]) 
            else:
                output+="  %7.2f \n"%element["Value"]
        output+=" -------------------------------\n"
        return output

    def set_value(self, value, key):
        '''
        Access to a list of the attributes, the occurence of "key" is checked 
        '''
        key_found=False
        for element in self.properties.eventFormat:
            if element['Name']==key:
                key_found=True
                # no array structure
                if value.__class__==quantities.quantity.Quantity:
                    aux=value.magnitude
                    size=aux.size
                    if size==1:
                        value=[value.magnitude]*value.units
                else:
                    if not isinstance(value, list):        
                        value=[value]
                    size=len(value)                
                if element['Size'] != size:
                    print "Size of the value for \"%s\" does not fit"%key
                    break
                if element.has_key('Dimension'):
                    if type(value).__name__ is 'Quantity':
                        value=UnitConverter.convertIntoSI(value, 
                                                      element['Dimension'])
                        if type(value).__name__== 'int':
                            if value==-1:
                                print "Wrong dimension for %s"%key
                                break
                    else:
                        print "%s values need the dimension \"%s\""%(key,element['Dimension'].dimensionality)
                        break
                [data_min, data_max]=self.get_size(element['DataType'])
                if min(value)<data_min or max(value)>data_max:
                    print value, "out of range of %s data type %s"%(key, element['DataType'])
                    break
                element['Value']=value  
        if key_found==False:
            print "Current Event does not contain \"%s\""%key

    def get_value(self, key):
        aux=[]
        for element in self.properties.eventFormat:
            if element['Name']==key:
                if element.has_key('Dimension'):
                    aux= element['Value']*element['Dimension']
                else:
                    aux= element['Value']
                break
        return aux

    def is_complete(self):
        for element in self.properties.eventFormat:
            if element['Value']==[]:
                print "Value for %s missed !"%(element['Name'])
                return False
        return True    

    def get_size(self,data_type):
        min = self.data_types[data_type][2][0]
        max = self.data_types[data_type][2][1]
        return [min, max]

    def value_is_inside(self, event, key, min, max):
        if event.has_key(key):
            value=event[key]
            if (value[0]>=min and value[0]<=max):
                return True
            else:
                return False
            
    def value_is_smaller(self, event, key, limit):
        if event.has_key(key):
            value=event[key]
            if value<limit:
                return True
            else:
                return False 


class ExtendedNetworkEvent(Event, ExtendedEventHandling):

    def __init__(self, channelProperties):
        '''
        Preparation of a event dict according to event format
        '''
        Event.__init__(self, subject=channelProperties.subject, content=[])
        self.properties=channelProperties
        ExtendedEventHandling.__init__(self, self.properties)
        self.event_coding_schema=self.prepare_event_mask(self.properties.eventFormat)
        
    def event_encoding(self):
        '''
        Maps the values of each event entry to the coding schema based on the struct methods
        '''
        output='struct.pack( self.event_coding_schema'
        for element in self.properties.eventFormat:
            if type(element['Value']) is list:
                for i in range(0, len(element['Value'])):
                    output+=(',%f'%element['Value'][i])
            else:
                output+=(',%f'%element['Value'])
        output+=')'
        self.size= len( eval(output))
        return eval(output)       
        
    def prepare_event_mask(self,eventFormat):
        format = ""
        for element in eventFormat:
            try:
                symbol = self.data_types[element['DataType']]
                for i in range(0,element['Size']):
                    format=format + symbol[0]
            except:
                print "Unknown data type in datasheet !!!"
        return format   

class ExtendedSensorEvent(ExtendedEventHandling):

    def __init__(self, sensorProperties):
        ExtendedEventHandling.__init__(self, sensorProperties)
        self.properties=sensorProperties      
        

